home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
EnigmA Amiga Run 1995 November
/
EnigmA AMIGA RUN 02 (1995)(G.R. Edizioni)(IT)[!][issue 1995-11][Skylink CD].iso
/
earcd
/
program
/
misc
/
fpl-v13.lha
/
fpl
/
src
/
hash.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-08-22
|
32KB
|
1,163 lines
/******************************************************************************
* FREXX PROGRAMMING LANGUAGE *
******************************************************************************
hash.c
Functions for FPL hash tables and sorting!
*****************************************************************************/
/************************************************************************
* *
* fpl.library - A shared library interpreting script langauge. *
* Copyright (C) 1992-1994 FrexxWare *
* Author: Daniel Stenberg *
* *
* This program is free software; you may redistribute for non *
* commercial purposes only. Commercial programs must have a written *
* permission from the author to use FPL. FPL is *NOT* public domain! *
* Any provided source code is only for reference and for assurance *
* that users should be able to compile FPL on any operating system *
* he/she wants to use it in! *
* *
* You may not change, resource, patch files or in any way reverse *
* engineer anything in the FPL package. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* *
* Daniel Stenberg *
* Ankdammsgatan 36, 4tr *
* S-171 43 Solna *
* Sweden *
* *
* FidoNet 2:201/328 email:dast@sth.frontec.se *
* *
************************************************************************/
#ifdef AMIGA
#include <exec/types.h>
#include <proto/exec.h>
#include <dos.h>
#else
#include <stdio.h>
#endif
#include "script.h"
#include "debug.h"
#include <limits.h>
#ifdef DEBUG
#include <stdio.h>
#endif
static ReturnCode REGARGS AddIdentifier(struct Data *, struct Identifier *);
static ReturnCode INLINE InitHash(struct Data *);
static unsigned long INLINE Gethash(uchar *);
static void * INLINE Init(struct Data *, long ASM (*)(AREG(0) void *), unsigned long *);
static ReturnCode REGARGS SetTags(struct Data *, unsigned long *);
static ReturnCode INLINE Hijack(struct Data *, struct Identifier *);
ReturnCode REGARGS
RenameIdentifier(struct Data *scr,
struct Identifier *ident, /* existing identifier */
uchar *newname) /* new name */
{
ReturnCode ret;
struct Identifier *nident;
ret = GetIdentifier(scr, newname, &nident);
if(ret != FPLERR_IDENTIFIER_NOT_FOUND) {
return FPLERR_IDENTIFIER_USED; /* !!! */
}
if(ident->flags&FPL_KEYWORD) {
/*
* Nonononono... we have to draw the limit somewhere!!!
* We really can't allow someone changing the keywords!!!
*/
return FPLERR_IDENTIFIER_USED;
}
/*
* Let's take the old one out of its chains!
*/
if(ident->prev) {
/* If there is a previous member */
ident->prev->next=ident->next;
}
else {
/* if this was the first in the list */
scr->hash[ident->hash%scr->hash_size]=ident->next;
}
if(ident->next) {
ident->next->prev=ident->prev;
}
if(ident->flags&(FPL_INTERNAL_FUNCTION|FPL_KEYWORD|FPL_EXTERNAL_FUNCTION)) {
if(ident->flags&FPL_DEALLOC_NAME_ANYWAY) {
/* Oh well, this has already been renamed once! */
FREE_KIND(ident->name);
}
else
ident->flags |= FPL_DEALLOC_NAME_ANYWAY;
/* this have to be known since this kind of functions regularly uses
names in the user-area which never get freed by us! */
}
else {
FREE_KIND(ident->name);
}
STRDUPA(ident->name, newname);
CALL( AddIdentifier(scr, ident));
return ret;
}
#ifndef AMIGA /* if not using SAS/C on Amiga */
#ifdef VARARG_FUNCTIONS
long fplAddFunctionTags(void *anchor, uchar *name, long ID, uchar rtrn,
uchar *format, ...)
{
va_list tags;
long ret;
va_start(tags, format); /* get parameter list */
ret = fplAddFunction(anchor, name, ID, rtrn, format, (unsigned long *)tags);
va_end(tags)
return ret;
}
#else
long fplAddFunctionTags(void *anchor, uchar *name, long ID, uchar rtrn,
uchar *format, unsigned long tags, ...)
{
return(fplAddFunction(anchor, name, ID, rtrn, format, &tags));
}
#endif
#endif
/**********************************************************************
*
* int fplAddFunction();
*
* User frontend to AddIdentifier().
*
*****/
ReturnCode PREFIX
fplAddFunction(AREG(0) struct Data *scr, /* pointer to struct Data */
AREG(1) uchar *name, /* name of function */
DREG(0) long ID, /* function ID */
DREG(1) uchar rtrn, /* return type */
AREG(2) uchar *format, /* format string */
AREG(3) unsigned long *tags) /* taglist pointer */
{
ReturnCode ret;
struct Identifier *ident;
#ifdef DEBUGMAIL
DebugMail(scr, MAIL_FUNCTION, 500, "fplAddFunction");
#endif
if(!scr)
return(FPLERR_ILLEGAL_ANCHOR);
ident=MALLOCA(sizeof(struct Identifier));
if(!ident)
return(FPLERR_OUT_OF_MEMORY);
memset(&ident->data.external, 0, sizeof(struct ExternalFunction));
while(tags && *tags) {
switch(*tags++) {
case FPLTAG_USERDATA:
ident->data.external.data=(void *)*tags;
break;
case FPLTAG_FUNCTION:
ident->data.external.func=(long (*)(void *))*tags;
break;
}
tags++; /* next! */
}
ident->name = name;
ident->data.external.ID = ID;
ident->data.external.ret = rtrn;
ident->data.external.format = format;
ident->flags = FPL_EXTERNAL_FUNCTION|FPL_GLOBAL_SYMBOL|FPL_EXPORT_SYMBOL;
ident->file = "<user>"; /* User added! */
ident->func = NULL; /* everywhere! */
ident->level = 0;
CALL(AddIdentifier(scr, ident));
return(FPL_OK);
}
/**********************************************************************
*
* int fplDelFunction();
*
* User frontend to DelIdentifier().
*
******/
ReturnCode PREFIX fplDelFunction(AREG(0) struct Data *scr,
AREG(1) uchar *name)
{
ReturnCode ret;
#ifdef DEBUGMAIL
DebugMail(scr, MAIL_FUNCTION, 500, "fplDelFunction");
#endif
if(!scr)
return(FPLERR_ILLEGAL_ANCHOR);
CALL(DelIdentifier(scr, name, NULL));
return(FPL_OK);
}
/**********************************************************************
*
* int AddVar();
*
* Frontend to the AddIdentifier function.
*
* This routine adds a member to the linked list of local variable names.
* That list exists to enable easy and fast removal of local variables
* when leaving a block within which local variables has been declared!
*
* Make sure that the name member data is static as long we need this list
* cause this routine doesn't copy that name, simply points to it!
*
*****/
ReturnCode REGARGS
AddVar(struct Data *scr, /* pointer to struct Data */
struct Identifier *ident,/* identifier struct pointer */
struct Local **local)
{
ReturnCode ret;
struct Local *temp;
if(ret=AddIdentifier(scr, ident))
;
else {
GETMEM(temp, sizeof(struct Local));
temp->next=*local;
temp->ident=ident;
*local=temp;
}
return(ret);
}
/**********************************************************************
*
* AddLevel();
*
* This function adds a NULL-name in the local symbol list to visualize
* the beginning of a new variable level!
*
*******/
ReturnCode REGARGS
AddLevel(struct Data *scr)
{
struct Local *temp;
GETMEM(temp, sizeof(struct Local));
temp->next=scr->locals;
temp->ident=NULL;
scr->locals=temp;
return(FPL_OK);
}
/**********************************************************************
*
* int DelLocalVar()
*
* This routine deletes all members to the linked list of local variable
* names. Call this routine every time you leave a local level. Deletes
* all variables and the following NULL name!
*
*****/
ReturnCode REGARGS
DelLocalVar(struct Data *scr,
struct Local **local)
{
/* This removes only all listed symbols! */
struct Identifier *ident;
while(*local) {
struct Local *temp=(*local)->next;
ident=(*local)->ident;
FREE(*local);
*local=temp;
if(ident)
DelIdentifier(scr, NULL, ident); /* delete it for real */
else
break;
}
return(FPL_OK);
}
/**********************************************************************
*
* int AddIdentifier()
*
* This function adds the function to the hash table according to all
* parameters.
*
* If the hash member of the Data structure is NULL, the hash table
* will be inited. No not init the hash list if you don't have to cause
* that sure is a peep hole in the performance...
*
*******/
static ReturnCode REGARGS
AddIdentifier(struct Data *scr,
struct Identifier *ident)
{
unsigned long hash; /* hash number of the identifier */
struct Identifier **add; /* where to store the pointer to this identifier */
struct Identifier *prev=NULL; /* pointer to previous hash structure */
struct Identifier *next; /* pointer to next hash structure */
ReturnCode ret;
hash=Gethash(ident->name);
add=(struct Identifier **)&scr->hash[hash % scr->hash_size];
while(*add) {
if((*add)->hash==hash) {
/* they were identical */
if(ident->flags&FPL_FUNCTION &&
!strcmp((*add)->name, ident->name) &&
/*
PREV STOOPID WAY:
(!ident->file || !strcmp(ident->file, (*add)->file))) { */
(ident->flags&FPL_EXPORT_SYMBOL || !strcmp(ident->file, (*add)->file))) {
/* if it's already there, fail!!! */
return FPLERR_IDENTIFIER_USED;
} else
/* add it here! */
break;
} else if((*add)->hash>hash) {
/* continue search for a place to insert */
/* 'add' now points to the pointer */
prev=(*add);
add=(struct Identifier **)&((*add)->next);
} else {
/* insert it here! */
prev=(*add)->prev;
break;
}
}
next=(*add);
*add=ident;
(*add)->hash=hash;
(*add)->prev=prev;
(*add)->next=next;
if(next)
next->prev=ident;
return(FPL_OK);
}
/**********************************************************************
*
* int GetIdentifier();
*
* Sets the pointer to the Identifier structure to which the name
* fits, in the third argument.
*
*****/
#ifdef DEBUG
int hashed=0;
int max_hashed=0;
#endif
ReturnCode REGARGS
GetIdentifier(struct Data *scr,
uchar *name,
struct Identifier **ident)
{
ReturnCode ret;
struct Identifier *get;
unsigned long hash=Gethash(name);
get=scr->hash[hash%scr->hash_size];
#ifdef DEBUG
hashed=0;
#endif
while(get) {
if(
(get->hash==hash) &&
/* identical hash value! */
!strcmp(get->name, name) &&
/* identical name! */
(get->flags&(FPL_GLOBAL_SYMBOL|FPL_EXPORT_SYMBOL) ||
(get->func==scr->func && get->level<=scr->varlevel)) &&
/* If not global, declared under the *same* function, in this or
a lower level! */
(get->flags&FPL_EXPORT_SYMBOL || !strcmp(get->file, scr->prog->name))
/* If not cross-file, the same file! */
) {
/* this is it! */
*ident=get;
#ifdef DEBUG
if(hashed>max_hashed)
max_hashed=hashed;
#endif
if(get->flags&FPL_EXTERNAL_VARIABLE) {
CALL(Hijack(scr, get));
}
else if(scr->flags&FPLDATA_ISOLATE && get->flags&FPL_EXPORT_SYMBOL) {
/*
* Isolated and exported symbol... really?
*/
if((get->flags&(FPL_FUNCTION|FPL_KEYWORD) == FPL_INSIDE_FUNCTION) ||
get->flags&FPL_VARIABLE) {
/*
* Nope, this symbol shouldn't get returned!
*/
break;
}
}
#ifdef DEBUGMAIL
DebugMail(scr, MAIL_IDENTIFIER_ACCESS, 0, get);
#endif
return FPL_OK;
} else if(get->hash<hash)
/* we've been searching through all possible alternatives! */
break;
#ifdef DEBUG
hashed++;
#endif
get=get->next;
}
*ident=NULL;
return FPLERR_IDENTIFIER_NOT_FOUND;
}
#ifndef AMIGA /* if not using SAS/C on Amiga */
#ifdef VARARG_FUNCTIONS
long fplAddVariableTags(void *anchor, uchar *name, long ID, uchar type,
void *defvalue, ...)
{
va_list tags;
long ret;
va_start(tags, format); /* get parameter list */
ret = fplAddVariable(anchor, name, ID, type, defvalue, (unsigned long *)tags);
va_end(tags)
return ret;
}
#else
long fplAddVariableTags(void *anchor, uchar *name, long ID, uchar type,
void *defvalue, unsigned long tags, ...)
{
return fplAddVariable(anchor, name, ID, type, defvalue, &tags);
}
#endif
#endif
/**********************************************************************
*
* int fplAddVariable();
*
* User frontend to AddIdentifier(). New in version 10!
*
*****/
ReturnCode PREFIX
fplAddVariable(AREG(0) struct Data *scr, /* pointer to struct Data */
AREG(1) uchar *name, /* name of variable */
DREG(0) long ID, /* variable ID */
DREG(1) uchar type, /* variable type */
AREG(2) void *defvalue, /* default value */
AREG(3) unsigned long *tags) /* taglist pointer */
{
ReturnCode ret;
struct Identifier *ident;
#ifdef DEBUGMAIL
DebugMail(scr, MAIL_FUNCTION, 500, "fplAddVariable");
#endif
if(!scr)
return(FPLERR_ILLEGAL_ANCHOR);
GETMEMA(ident, sizeof(struct Identifier));
memset(&ident->data.variable, 0, sizeof(struct fplVariable));
ident->name = name;
ident->data.variable.ID = ID;
ident->flags = FPL_EXTERNAL_VARIABLE|FPL_GLOBAL_SYMBOL|FPL_EXPORT_SYMBOL|
(type == FPL_STRARG? FPL_STRING_VARIABLE:FPL_INT_VARIABLE)|
FPL_READONLY;
if(type == FPL_INTARG) {
GETMEM(ident->data.variable.var.val32, sizeof(long));
ident->data.variable.var.val32[0] = (long) defvalue;
}
else
if(defvalue) {
register long len = (long)strlen((uchar *)defvalue);
if(len) {
GETMEM(ident->data.variable.var.str, sizeof(struct fplStr *));
GETMEM(ident->data.variable.var.str[0], len + sizeof(struct fplStr));
ident->data.variable.var.str[0]->len = len;
ident->data.variable.var.str[0]->alloc = len;
memcpy(ident->data.variable.var.str[0]->string, defvalue,
len);
ident->data.variable.var.str[0]->string[len] = '\0'; /* Z-terminate */
}
}
ident->file = "<user>"; /* Used added! */
ident->func = NULL; /* everywhere! */
ident->level = 0;
CALL(AddIdentifier(scr, ident));
return(FPL_OK);
}
/*************************************************************************
*
* Hijack();
*
* This function gets called whenever an external variable has been selected
* by GetIdentifier().
*
******/
static ReturnCode INLINE Hijack(struct Data *scr, struct Identifier *ident)
{
struct fplArgument pass;
struct fplMsg *msg;
ReturnCode ret;
memset(&pass, 0, sizeof(struct fplArgument));
pass.argc=0;
pass.name=ident->name;
pass.ID=ident->data.variable.ID;
pass.key=scr;
pass.variable = (void *)
(ident->flags&FPL_STRING_VARIABLE?
(ident->data.variable.var.str &&ident->data.variable.var.str[0]?
ident->data.variable.var.str[0]->string:""):
(void *)ident->data.variable.var.val32[0]);
CALL(InterfaceCall(scr, &pass, scr->function));
if(ident->flags&FPL_INT_VARIABLE) {
/*
* Integer variable!
*/
CALL(GetMessage(scr, FPLMSG_RETURN, &msg));
if(msg && msg->flags&FPLMSG_FLG_INT) {
ident->data.variable.var.val32[0]=(long)msg->message[0];
CALL(DeleteMessage(scr, msg));
}
} else {
/*
* String variable!
*/
CALL(GetMessage(scr, FPLMSG_RETURN, &msg));
if(msg && msg->flags&FPLMSG_FLG_STRING) {
if(!ident->data.variable.var.str) {
GETMEMA(ident->data.variable.var.str, sizeof(struct fplStr *));
}
else if(ident->data.variable.var.str[0]) {
FREEA(ident->data.variable.var.str[0]);
}
ident->data.variable.var.str[0]=(struct fplStr *)msg->message[0];
/*
* Make the string to be static always!
*/
SwapMem(scr, ident->data.variable.var.str[0], MALLOC_STATIC);
DeleteMessage(scr, msg);
}
}
return(FPL_OK);
}
/**********************************************************************
*
* int InitHash()
*
* Initialize the hash table. Simple and quick!
*
*****/
struct ShitData {
uchar *name;
long ID;
uchar ret;
uchar *format;
};
struct MoreShitData {
uchar *name;
long ID;
long flags;
};
static ReturnCode INLINE InitHash(struct Data *scr)
{
ReturnCode ret;
static struct ShitData internal_functions[]={
{"abs", FNC_ABS, 'I', "I"},
{"atoi", FNC_ATOI, 'I', "S"},
{"closelib", FNC_CLOSELIB, 'I', "S"}, /* amiga only */
{"debug", FNC_DEBUG, 'I', "i"},
{"eval", FNC_EVAL, 'I', "S"},
{"exists", FNC_EXISTS, 'I', "Si"},
{"interpret", FNC_INTERPRET, 'I', "S"},
{"itoa", FNC_ITOA, 'S', "I"},
{"itoc", FNC_ITOC, 'S', "I"},
{"joinstr", FNC_JOINSTR, 'S', "s>"},
{"ltostr", FNC_LTOSTR, 'S', "Ii"},
{"openlib", FNC_OPENLIB, 'I', "SI"}, /* amiga only */
{"rename", FNC_RENAME, 'I', "SS"},
{"sprintf", FNC_SPRINTF, 'S', "Sa>"},
{"sscanf", FNC_SSCANF, 'I', "SSa>"},
{"strcmp", FNC_STRCMP, 'I', "SS"},
{"stricmp", FNC_STRICMP, 'I', "SS"},
{"strlen", FNC_STRLEN, 'I', "S"},
{"strncmp", FNC_STRNCMP, 'I', "SSI"},
{"strnicmp", FNC_STRNICMP, 'I', "SSI"},
{"strstr", FNC_STRSTR, 'I', "SSi"},
{"stristr", FNC_STRISTR, 'I', "SSi"},
{"strtol", FNC_STRTOL, 'I', "Si"},
{"substr", FNC_SUBSTR, 'S', "SII"},
};
/* FPL keywords. "else" is not included (treated special). Is is
defines as KEYWORD_ELSE */
static struct MoreShitData keywords[]={
{"auto", CMD_AUTO, FPL_KEYWORD_DECLARE},
{"break", CMD_BREAK, 0},
{"case", CMD_CASE, 0},
{"char", CMD_INT, FPL_KEYWORD_DECLARE|FPL_CHAR_VARIABLE},
{"const", CMD_CONST, FPL_KEYWORD_DECLARE},
{"continue", CMD_CONTINUE, 0},
{"default", CMD_DEFAULT, 0},
{"do", CMD_DO, 0},
{"double", CMD_DOUBLE, FPL_IGNORE},
{"enum", CMD_ENUM, FPL_IGNORE},
{"exit", CMD_EXIT, 0},
{"export", CMD_EXPORT, FPL_KEYWORD_DECLARE},
{"float", CMD_FLOAT, FPL_IGNORE},
{"for", CMD_FOR, 0},
{"if", CMD_IF, 0},
{"int", CMD_INT, FPL_KEYWORD_DECLARE},
{"long", CMD_INT, FPL_KEYWORD_DECLARE},
{"register",CMD_REGISTER, FPL_KEYWORD_DECLARE},
{"resize", CMD_RESIZE, 0},
{"return", CMD_RETURN, 0},
{"short", CMD_INT, FPL_KEYWORD_DECLARE|FPL_SHORT_VARIABLE},
{"signed", CMD_SIGNED, FPL_KEYWORD_DECLARE|FPL_IGNORE},
{"static", CMD_STATIC, FPL_KEYWORD_DECLARE},
{"string", CMD_STRING, FPL_KEYWORD_DECLARE},
{"struct", CMD_STRUCT, FPL_IGNORE},
{"switch", CMD_SWITCH, 0},
{"typedef", CMD_TYPEDEF, 0},
{"union", CMD_UNION, FPL_IGNORE},
{"unsigned",CMD_UNSIGNED, FPL_KEYWORD_DECLARE|FPL_IGNORE},
{"void", CMD_VOID, FPL_KEYWORD_DECLARE},
{"volatile",CMD_VOLATILE, FPL_KEYWORD_DECLARE|FPL_IGNORE},
{"while", CMD_WHILE, 0},
};
long i;
struct Identifier *ident;
GETMEMA(scr->hash, sizeof(struct Identifier *)* scr->hash_size);
memset((void *)scr->hash, 0, sizeof(struct Identifier *)*scr->hash_size);
/*
* The hash table initialization gives us a brilliant chance to bring up
* the execution speed even more by inserting the few internal functions
* into this same table. The functions will then act *EXACTLY* the same
* and we can shorten the code and much easier write internal functions
* that return strings...
*/
for(i=0; i<sizeof(internal_functions)/sizeof(struct ShitData);i++) {
GETMEMA(ident, sizeof(struct Identifier));
ident->name=internal_functions[i].name;
ident->data.external.ID=internal_functions[i].ID;
ident->data.external.ret=internal_functions[i].ret;
ident->data.external.format=internal_functions[i].format;
ident->flags=FPL_INTERNAL_FUNCTION|FPL_EXPORT_SYMBOL;
ident->level=0;
ident->func=NULL; /* all functions */
ident->file= "<FPL>"; /* internal */
ret=AddIdentifier(scr, ident);
if(ret)
break;
}
for(i=0; i<sizeof(keywords)/sizeof(struct MoreShitData);i++) {
GETMEMA(ident, sizeof(struct Identifier));
ident->name=keywords[i].name;
ident->data.external.ID=keywords[i].ID; /* dirty enum work! */
ident->flags=FPL_EXPORT_SYMBOL|FPL_KEYWORD|keywords[i].flags;
ident->level=0;
ident->func=NULL; /* all functions */
ident->file= "<FPL>"; /* internal */
ret=AddIdentifier(scr, ident);
if(ret)
break;
}
return(ret);
}
/**********************************************************************
*
* int Gethash();
*
* Return the hash number for the name received as argument.
*
*****/
static unsigned long INLINE Gethash(uchar *name)
{
unsigned long hash=0;
while(*name)
hash=(hash<<1)+*name+++(hash&(1<<31)?-2000000000:0);
return(hash);
}
/**********************************************************************
*
* void Free();
*
* This function frees the resources used by this FPL session.
*
***********/
void PREFIX fplFree(AREG(0) struct Data *scr)
{
struct Data onstack;
long retval;
#ifdef DEBUGMAIL
DebugMail(scr, MAIL_FUNCTION, 500, "fplFree");
#endif
onstack=*scr; /* copy the entire struct */
scr=&onstack; /* use the `stack-struct' */
DelProgram(scr, NULL); /* remove all programs from memory, some might be
Lock()'ed! */
#ifdef AMIGA /* only amiga supports funclibs! */
CloseLib(scr, NULL, TRUE, &retval); /* force close of all funclibs */
#endif
FREEALL();
FREEALLA();
}
/**********************************************************************
*
* int DelIdentifier()
*
* Delete an identifier from the hash table. Specify 'name' or 'ident'.
*
******/
ReturnCode REGARGS
DelIdentifier(struct Data *scr,
uchar *name, /* only needed if 'ident' is NULL! */
struct Identifier *ident)
{
ReturnCode ret=FPL_OK;
long i;
struct fplVariable *var;
if(!ident) {
/* Get the structure pointer */
CALL(GetIdentifier(scr, name, &ident));
}
/* Link the previous member in the list to the next member */
if(ident->prev)
/* If there is a previous member */
ident->prev->next=ident->next;
else
/* if this was the first in the list */
scr->hash[ident->hash%scr->hash_size]=ident->next;
if(ident->next)
ident->next->prev=ident->prev;
/*
* If it is any kind of funtion, all the data the pointers points to
* should (in the specs) be static and should therefore *NOT* be
* freed here!
*
* Notice that even internal functions are possible to remove here...
*/
if(ident->flags & FPL_VARIABLE) {
/*
* It's a variable identifier. Free some members:
*/
var=&ident->data.variable;
if(ident->flags & FPL_REFERENCE) {
/* only keep a reference pointer! */
}
else {
if(ident->flags & FPL_STRING_VARIABLE) {
/* it's a string array! */
for(i=0; i<var->size; i++)
if(var->var.str[i]) {
FREE_KIND(var->var.str[i]);
}
}
if(var->num)
FREE_KIND(var->dims);
FREE_KIND(var->var.val);
}
} else if(ident->flags&FPL_INSIDE_FUNCTION &&
ident->data.inside.format) {
FREE_KIND(ident->data.inside.format);
}
if((ident->flags&FPL_EXTERNAL_FUNCTION)||
(ident->flags&(FPL_INTERNAL_FUNCTION|FPL_KEYWORD))) {
/* internal or external function/keyword */
if(ident->flags&FPL_DEALLOC_NAME_ANYWAY)
/* this name has been renamed into this! */
FREE_KIND(ident->name);
FREEA(ident);
} else {
FREE_KIND(ident->name);
FREE_KIND(ident);
}
return(ret);
}
#ifndef AMIGA /* if not using SAS/C on Amiga */
#ifdef VARARG_FUNCTIONS
void *fplInitTags(long (*func)(void *), ...)
{
va_list tags;
void *ret;
va_start(tags, func); /* get parameter list */
ret = fplInit(func, (unsigned long *)tags);
va_end(tags)
return ret;
}
#else
void *fplInitTags(long (*func)(void *), unsigned long tags, ...)
{
return(fplInit(func, (unsigned long *)&tags));
}
#endif
#endif
/**********************************************************************
*
* fplInit();
*
* Initialize a lot of FPL internal structures and references. Returns
* NULL if anything went wrong!
*
*******/
void * ASM fplInit(AREG(0) long (*function) (void *),
/* function handler pointer */
AREG(1) unsigned long *tags) /* taglist */
{
struct Data point;
struct Data *scr;
void *init;
scr=&point;
#ifdef AMIGA
/* Store all register before loading index register */
StoreRegisters(scr);
geta4();
#endif
init=Init(&point, function, tags);
if(!init)
FREEALLA();
#ifdef DEBUGMAIL
DebugMail(scr, MAIL_FUNCTION, 500, "fplInit");
#endif
return(init);
}
static void * INLINE Init(struct Data *scr, /* stack oriented */
long ASM (*function) (AREG(0) void *),
unsigned long *tags) /* taglist */
{
ReturnCode ret;
uchar *buffer;
struct Data *ptr;
#ifdef AMIGA
long registers[11];
memcpy(registers, scr->registers, sizeof(long)*11);
#endif
/* Set default that just might get changed in SetTags(); */
memset(scr, 0, sizeof(struct Data)); /* NULLs everything! */
scr->Alloc=DefaultAlloc;
scr->Dealloc=DefaultDealloc;;
scr->hash_size=FPL_HASH_SIZE;
scr->runs=0;
InitFree(scr); /* init memory caches */
#ifdef AMIGA
memcpy(scr->registers, registers, sizeof(long)*11);
scr->stack_size=FPL_MIN_STACK;
scr->stack_max=FPL_MAX_STACK;
scr->stack_limit=FPL_MAX_LIMIT;
scr->stack_margin=FPLSTACK_MINIMUM;
#endif
SetTags(scr, tags); /* read tags and set proper members */
buffer=(uchar *)MALLOCA(BUF_SIZE);
if(!buffer)
/* fail! */
return(NULL);
#ifdef AMIGA
#pragma msg 225 ignore /* ignore the 225 warnings that occur on the following
assign! */
#endif
scr->function=(long ASM (*)(AREG(0) void *))function;
#ifdef AMIGA
#pragma msg 225 warning /* enable the 225 warnings again! */
#endif
scr->buf=buffer;
#if defined(AMIGA) && defined(SHARED)
scr->stack_base=MALLOCA(scr->stack_size);
if(!scr->stack_base)
return(NULL);
scr->intern_stack = (long)scr->stack_base + scr->stack_size;
Forbid();
scr->task = FindTask(NULL); /* get pointer to our task! */
Permit();
#endif
if(ret=InitHash(scr))
return(NULL);
ptr=(struct Data *)MALLOCA(sizeof(struct Data));
if(ptr)
*ptr=*scr; /* copy the entire structure! */
return((void *)ptr);
}
#ifndef AMIGA /* if not using SAS/C on Amiga */
#ifdef VARARG_FUNCTIONS
long fplResetTags(void *anchor, ...)
{
va_list tags;
long ret;
va_start(tags, anchor); /* get parameter list */
ret = fplReset(anchor, (unsigned long *)tags);
va_end(tags)
return ret;
}
#else
long fplResetTags(void *anchor, unsigned long tags, ...)
{
return(fplReset(anchor, &tags));
}
#endif
#endif
/**********************************************************************
*
* fplReset();
*
* This function is used to change or add tags to FPL. All tags
* available for fplFree() is legal. Not changed tags will remain
* as they were before this call!
*
* I had to insert this function since I found out that I wanted to
* alter the userdata in my application using FPL, and that was hard
* doing so (nice) without this change.
*
* Library front end to SetTags();
*
*****/
ReturnCode PREFIX fplReset(AREG(0) struct Data *scr,
AREG(1) unsigned long *tags)
{
#ifdef DEBUGMAIL
DebugMail(scr, MAIL_FUNCTION, 500, "fplReset");
#endif
if(!scr)
return FPLERR_ILLEGAL_ANCHOR;
return SetTags(scr, tags);
}
/**********************************************************************
*
* SetTags();
*
* Read the taglist supplied in the second parameter, and set all data
* according to those.
*
*****/
static ReturnCode REGARGS
SetTags(struct Data *scr,
unsigned long *tags)
{
if(!scr)
return(FPLERR_ILLEGAL_ANCHOR);
while(tags && *tags) {
switch(*tags++) {
#ifdef AMIGA
#pragma msg 225 ignore /* ignore the 225 warnings that occur on the following
four assigns! */
#endif
case FPLTAG_INTERVAL:
scr->interfunc=(long ASM (*)(AREG(0) void *))*tags;
break;
case FPLTAG_INTERNAL_ALLOC:
scr->Alloc=(void * ASM (*)(DREG(0) long,
AREG(0) void *))*tags;
break;
case FPLTAG_INTERNAL_DEALLOC:
scr->Dealloc=(void ASM (*)(AREG(1) void *,
DREG(0) long,
AREG(0) void *))*tags;
break;
#ifdef AMIGA
#pragma msg 225 warning /* enable the 225 warning again for correct program
checking! */
#endif
case FPLTAG_REREAD_CHANGES:
scr->flags = BitToggle(scr->flags, FPLDATA_REREAD_CHANGES, *tags);
break;
case FPLTAG_FLUSH_NOT_IN_USE:
scr->flags = BitToggle(scr->flags, FPLDATA_FLUSH_NOT_IN_USE, *tags);
break;
case FPLTAG_KIDNAP_CACHED:
scr->flags = BitToggle(scr->flags, FPLDATA_KIDNAP_CACHED, *tags);
break;
case FPLTAG_PREVENT_RUNNING_SAME:
scr->flags = BitToggle(scr->flags, FPLDATA_PREVENT_RUNNING_SAME, *tags);
break;
case FPLTAG_HASH_TABLE_SIZE:
if(*tags>FPL_MIN_HASH)
scr->hash_size=*tags;
break;
case FPLTAG_USERDATA:
scr->userdata=(void *)*tags;
break;
case FPLTAG_ALLFUNCTIONS:
scr->flags = BitToggle(scr->flags, FPLDATA_ALLFUNCTIONS, *tags);
break;
case FPLTAG_NESTED_COMMENTS:
scr->flags = BitToggle(scr->flags, FPLDATA_NESTED_COMMENTS, *tags);
break;
case FPLTAG_CACHEALLFILES:
if(*tags) {
scr->flags|=FPLDATA_CACHEALLFILES;
if(*tags == FPLCACHE_EXPORTS)
scr->flags|=FPLDATA_CACHEEXPORTS;
} else
scr->flags &= ~(FPLDATA_CACHEALLFILES|FPLDATA_CACHEEXPORTS);
break;
#ifdef STRING_STACK
case FPLTAG_STRINGSTACK:
scr->strings_in_stack_max = (long)*tags;
if( scr->strings_in_stack_max>0 ) {
if(scr->stringsstack) {
FREEA(scr->stringsstack);
}
GETMEMA(scr->stringstack, scr->strings_in_stack_max *
sizeof( struct StringStack ));
}
break;
#endif
#ifdef AMIGA
case FPLTAG_STACK:
/* Only change stack if the required size is large enough! */
if(*tags>FPL_MIN_STACK)
scr->stack_size=(long)*tags;
break;
case FPLTAG_MAXSTACK:
/* Only change this if the required size is large enough! */
if(*tags>FPL_MIN_STACK)
scr->stack_max=(long)*tags;
break;
case FPLTAG_STACKLIMIT:
/* Only change this if the required size is large enough! */
if(*tags>FPL_MIN_STACK)
scr->stack_limit=(long)*tags;
break;
case FPLTAG_MINSTACK:
/* Only change this if the required size is larger than default! */
if(*tags>FPLSTACK_MINIMUM)
scr->stack_margin=*tags;
break;
#endif
case FPLTAG_IDENTITY:
/* new from version 9: Host process identifier! */
scr->identifier = (uchar *)(*tags);
break;
case FPLTAG_DEBUG:
scr->flags = BitToggle(scr->flags, FPLDATA_DEBUG_GLOBAL, *tags);
break;
case FPLTAG_ERROR_BUFFER:
scr->error = (uchar *)(*tags);
break;
}
tags++; /* next! */
}
return(FPL_OK);
}
long REGARGS
BitToggle(long original, /* Original 32 bits */
long bit, /* alternate bit pattern */
long OnOff) /* Or/And boolean, TRUE==OR, FALSE==AND */
{
if(OnOff)
return ( original | bit );
else
return ( original & ~bit );
}